package main

import (
	"io"
	"log"
	"net"
	"net/http"
	"os"
	"sync"
	"time"

	"golang.org/x/net/ipv6"
)

var filePath string = ""
var fileName string = ""
var fileLength int64 = 0
var fileHash string = ""
var blockHash = make([]string, 0)
var sliceHash = make([]uint32, 0)
var totalSlice int64 = 0 //最大值应该为2^31-1
var networkSpeed int
var serverWebPort = "9980"
var broadcastMagicPort = 9901
var broadcastFilePort = 9902
var broadcastGroup = net.ParseIP("ff02::e1f1:4a05:72a0:5f11:e000") //文件多播组

var copyString = "局域网多播文件发送工具 v0.3.1 (2024-3-12)"

// 最大允许文件大小，程序设置决定最大值是(2^31-1)*32k≈64T,这里取32G，足够大多数用途
const maxFilelength int64 = 32 * 1024 * 1024 * 1024

// 最小值是10，对应1024,
// Udp包最大长度是65507, 但是考虑slice除了数据外，还有附加字节， 所以最大值15，对应32768
// 小slice会降低丢包率，但是增加丢包的绝对数量，增加服务器处理时间，导致HTTP并发处理出错概率大
const logSlice = 15

// 大的Block会提高传输速度，但是会导致单次传输的slice数量变大，单次丢包绝对值增大，
// 增加Block传送后服务器处理时间，有概率超过后处理总延时而出错
const logBlock = 28
const sliceLength = 1 << logSlice
const bufferLength = 1 << logBlock
const sliceOfBlock = 1 << (logBlock - logSlice)
const ControlPacketRepeat = 8 //同步信息包重复发送次数

var bufferMutex = sync.Mutex{}
var buffer = make([]byte, bufferLength)
var bufferZero = make([]byte, bufferLength)
var dataString = "DATA" //数据字符
var infoString = "INFO"
var beginBlockString = "BEGB"
var endBlockString = "ENDB"
var endFileString = "ENDF"
var magicNumber = "ELFYAOSBROADCASTFILETRANS"

func infiniteLoop() {
	for {
		time.Sleep(time.Second)
	}
}

func setupLogFile(logFileName string) (*os.File, error) {
	// 创建或打开一个日志文件
	logFile, err := os.OpenFile(logFileName, os.O_TRUNC|os.O_CREATE|os.O_WRONLY, 0644)
	if err != nil {
		return nil, err
	}

	// 设置日志默认输出为该文件
	log.SetOutput(logFile)

	// 可以设置前缀等格式
	log.SetFlags(log.LstdFlags | log.Lmicroseconds | log.Lshortfile)

	return logFile, nil
}

func getHttpReq(webPath string) (responseString string, err error) {
	// 构建请求对象
	req, err := http.NewRequest("GET", webPath, nil)
	if err != nil {
		return "", err
	}

	// 创建一个客户端实例
	client := &http.Client{}

	// 发送请求并获取响应
	resp, err := client.Do(req)
	if err != nil {
		return "", err
	}
	defer resp.Body.Close()

	// 读取响应体内容
	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return "", err
	}

	//返回响应体
	return string(body), nil

}

func now() string {
	var t = time.Now()
	return t.Format("2006-01-02 15:04:05.000")
}

func createConn(dst *net.UDPAddr) (*net.UDPConn, *ipv6.PacketConn, error) {
	//侦听适当的服务端口
	c, err := net.ListenUDP("udp6", dst)
	if err != nil {
		return nil, nil, err
	}
	//加入组播组，开始侦听指定网络接口上的组
	p := ipv6.NewPacketConn(c)
	if err := p.JoinGroup(nil, dst); err != nil {
		return nil, nil, err
	}
	return c, p, nil
}
